/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable array-callback-return */
import {
  CTX,
  execUILogic,
  INavViewMsg,
  UIActionUtil,
  calcNavParams,
  CodeListItem,
  ConfigService,
  ScriptFactory,
  ControllerEvent,
  ControlController,
  calcDeCodeNameById,
  ContextMenuController,
} from '@ibiz-template/runtime';
import dayjs from 'dayjs';
import {
  IDER1N,
  INavigatable,
  ISysCalendar,
  ISysCalendarItem,
} from '@ibiz/model-core';
import { IResourceScheduleTableState } from './resource-schedule-table.state';
import { IResourceScheduleTableEvent } from './resource-schedule-table.event';
import Variables from './resource-scheduler/constant/vars';
import { IGlobalConfig, IScheduleTask } from './resource-scheduler';

export class ResourceScheduleTableController extends ControlController<
  ISysCalendar,
  IResourceScheduleTableState
> {
  /**
   * 上下文菜单控制器
   * @author lxm
   * @date 2023-08-21 10:56:24
   * @type {{ [p: string]: ContextMenuController }}
   */
  contextMenus: { [p: string]: ContextMenuController } = {};

  get _evt(): ControllerEvent<IResourceScheduleTableEvent> {
    return this.evt;
  }

  /**
   * @description 开始时间
   * @type {Date}
   * @memberof ResourceScheduleTableController
   */
  startTime: Date = new Date();

  /**
   * @description 结束时间
   * @type {Date}
   * @memberof ResourceScheduleTableController
   */
  endTime: Date = new Date(Date.now() + 86400000 * 7);

  /**
   * 代码表数据集合
   *
   * @type {CodeListItem[]}
   * @memberof ResourceScheduleTableController
   */
  codeListItems?: CodeListItem[];

  /**
   * 配置存储服务
   *
   * @type {ConfigService}
   * @memberof ResourceScheduleTableController
   */
  config!: ConfigService;

  /**
   * 任务类型属性名称
   *
   * @readonly
   * @type {(string | void)}
   * @memberof ResourceScheduleTableController
   */
  get taskTypeField(): string | void {
    return this.controlParams.tasktypefield;
  }

  /**
   * @description 获取数据行为
   * @readonly
   * @type {string}
   * @memberof ResourceScheduleTableController
   */
  get getControlAction(): string {
    if (this.controlParams.getcontrolaction)
      return this.controlParams.getcontrolaction;
    return this.state.isCacheMode ? 'GetTemp' : 'get';
  }

  /**
   * Creates an instance of ControlController.
   * @param {T} model
   * @param {IContext} context
   * @param {IParams} [params={}]
   */
  constructor(
    model: ISysCalendar,
    context: IContext,
    params: IParams,
    ctx: CTX,
  ) {
    super(model, context, params, ctx);
    this.init();
  }

  async init(): Promise<void> {
    this.config = new ConfigService(
      this.model.appId!,
      'schedule_table',
      `task_color_options`,
    );

    const { taskColorOptions } = await this.loadConfig();
    await this.initTaskColorOptions(taskColorOptions);
  }

  /**
   * @description 初始化state的属性
   * @protected
   * @memberof ResourceScheduleTableController
   */
  protected initState(): void {
    super.initState();
    this.state.tasks = [];
    this.state.resources = [];
    this.state.data = {};
    this.state.isCacheMode = false;
  }

  /**
   * 初始化任务颜色配置
   *
   * @protected
   * @return {*}  {Promise<void>}
   * @memberof ResourceScheduleTableController
   */
  protected async initTaskColorOptions(
    _taskColorOptions: string | undefined,
  ): Promise<void> {
    const { groupCodeListId } = this.model;
    if (groupCodeListId) {
      const taskColorOptions = {};
      const app = ibiz.hub.getApp(this.context.srfappid);
      const codeList = await app.codeList.get(
        groupCodeListId,
        this.context,
        this.params,
      );
      const codeListItems: CodeListItem[] = [];
      codeList.forEach(_item => {
        codeListItems.push(_item);
        Object.assign(taskColorOptions, {
          [_item.value]: {
            taskColor: 'blue',
            taskBgColor: '#84ffff',
            taskAcitveBorderColor: 'red',
          },
        });
      });
      this.codeListItems = codeListItems;

      if (_taskColorOptions) {
        try {
          Object.assign(taskColorOptions, {
            ...JSON.parse(_taskColorOptions || '{}'),
          });
        } catch (error) {
          ibiz.log.error(error);
        }
      }
      this.setTaskColorOptions(taskColorOptions);
    }
  }

  /**
   * 设置任务颜色配置
   *
   * @param {IData} taskColorOptions
   * @memberof ResourceScheduleTableController
   */
  setTaskColorOptions(taskColorOptions: IData): void {
    this.state.taskColorOptions = taskColorOptions;
  }

  /**
   * 加载存储的数据
   *
   * @return {*}  {Promise<void>}
   * @memberof ResourceScheduleTableController
   */
  async loadConfig(): Promise<IData> {
    const res = await this.config.load();
    return res;
  }

  /**
   * 保存存储的数据
   *
   * @return {*}  {Promise<void>}
   * @memberof ResourceScheduleTableController
   */
  async saveConfig(): Promise<void> {
    const data: IData = {
      taskColorOptions: JSON.stringify(this.state.taskColorOptions),
    };
    await this.config.save(data);
  }

  /**
   * 加载主数据
   *
   * @return {*}  {Promise<void>}
   * @memberof ResourceScheduleTableController
   */
  async load(): Promise<void> {
    try {
      this.startLoading();
      const { sysCalendarItems } = this.model;
      const app = ibiz.hub.getApp(this.context.srfappid);
      if (sysCalendarItems) {
        const result = await app.deService.exec(
          this.model.appDataEntityId!,
          this.getControlAction,
          this.context,
          this.params,
          {},
        );
        if (result.ok && result?.data) {
          this.state.data = result.data;
          this.state.caption = result.data.name;
          await this.loadSchedule(true);
        }
      }
    } finally {
      await this.endLoading();
    }
  }

  /**
   * @description 获取查询参数
   * @private
   * @param {ISysCalendarItem} item
   * @returns {*}  {IParams}
   * @memberof ResourceScheduleTableController
   */
  private async getFetchParams(
    item: ISysCalendarItem,
    args: IData = {},
  ): Promise<IParams> {
    const params: IParams = { ...this.params };
    await this._evt.emit('onBeforeLoad', {
      params,
      data: [
        {
          calendarItem: item,
          startTime: dayjs(this.startTime).format('YYYY-MM-DD HH:mm:ss'),
          endTime: dayjs(this.endTime).format('YYYY-MM-DD HH:mm:ss'),
          ...args,
        },
      ],
    });
    return params;
  }

  /**
   * @description 加载排程数据
   * @param {boolean} [isInitialLoad] 是否为初始化加载
   * @returns {*}  {Promise<void>}
   * @memberof ResourceScheduleTableController
   */
  async loadSchedule(isInitialLoad: boolean): Promise<void> {
    try {
      if (!isInitialLoad) await this.startLoading();
      const { sysCalendarItems } = this.model;
      if (!sysCalendarItems) return;
      const app = ibiz.hub.getApp(this.context.srfappid);
      const fetch = async (
        item: ISysCalendarItem,
        args: IData = {},
      ): Promise<IData[]> => {
        const fetchAction = item.appDEDataSetId || 'fetchdefault';
        const params = await this.getFetchParams(item, args);
        const res = await app.deService.exec(
          item.appDataEntityId!,
          fetchAction,
          this.context,
          params,
          {},
        );
        return this.transformDatas(item.id!, res.data as IData[]);
      };
      // 通过日历项配置获取对应实体的数据，即资源和任务的数据
      const resourcesItem = sysCalendarItems.find(
        item => item.id === 'resource',
      );
      if (!resourcesItem) return;
      const resources = await fetch(resourcesItem, {
        data: this.state.data,
      });
      const tasksItem = sysCalendarItems.find(item => item.id === 'task');
      if (!tasksItem) return;
      const tasks = await fetch(tasksItem, {
        data: this.state.data,
        resources,
      });
      this.state.tasks = tasks || [];
      this.state.resources = resources || [];
      await this._evt.emit('onLoadSuccess', {
        isInitialLoad,
        data: [
          {
            tasks: this.state.tasks,
            resources: this.state.resources,
          },
        ],
      });
    } finally {
      if (!isInitialLoad) await this.endLoading();
    }
  }

  /**
   * 转换数据
   *
   * @param {string} key
   * @param {IData[]} items
   * @return {*}  {IData[]}
   * @memberof ResourceScheduleTableController
   */
  transformDatas(key: string, items: IData[]): IData[] {
    let results: IData[] = [];
    // 在日历的动态控件参数上配置了数据源字段映射， 值为taskfillmap ，表示是任务的数据源字段映射，值为resourcefillmap， 表示是资源的数据源字段映射
    if (this.controlParams[`${key}fillmap`]) {
      const fillmap = JSON.parse(this.controlParams[`${key}fillmap`]);
      results = items.map(item => {
        const tempItem: IData = {};
        Object.keys(fillmap).forEach(_key => {
          if (_key === 'start' || _key === 'end') {
            tempItem[_key] = new Date(item[fillmap[_key]]);
          } else {
            tempItem[_key] = item[fillmap[_key]];
          }
        });
        tempItem.data = item;
        return tempItem;
      });
    }
    return results;
  }

  protected async onCreated(): Promise<void> {
    await super.onCreated();

    // 处理上下文菜单，用于点击单元格或者任务时显示
    this.model.sysCalendarItems?.forEach((item: IData) => {
      if (item.decontextMenu?.detoolbarItems?.length) {
        this.contextMenus[item.id!] = new ContextMenuController(
          item.decontextMenu,
          this.context,
          this.params,
          this.ctx,
        );
      }
    });
    const { controls = [] } = this.model;
    const quickToolbar = controls.find(
      x => x.name === `${this.model.name!}_quicktoolbar`,
    );
    // 处理快速工具栏，用于点击表格空白区域时显示
    if (quickToolbar) {
      this.contextMenus[quickToolbar.id!] = new ContextMenuController(
        quickToolbar,
        this.context,
        this.params,
        this.ctx,
      );
    }

    // 上下文菜单控制器初始化
    await Promise.all(
      Object.values(this.contextMenus).map(menu => menu.created()),
    );

    await this.load();
  }

  /**
   * 计算是否存在自定义Htmljiaoben
   *
   * @param {string} type
   * @return {*}  {(string | undefined)}
   * @memberof ResourceScheduleTableController
   */
  calcHasRender(type: string): string | undefined {
    const tempItem = this.model.sysCalendarItems?.find(item => {
      return item.id === type;
    });
    if (
      tempItem?.controlRenders?.length &&
      tempItem.controlRenders[0].layoutPanelModel
    ) {
      let scriptCode = tempItem.controlRenders[0].layoutPanelModel;
      // 兼容单行脚本
      if (!scriptCode.includes('return')) {
        scriptCode = `return (${scriptCode})`;
      }
      return scriptCode;
    }
  }

  /**
   * 获取自定义Html
   *
   * @param {string} type
   * @param {*} [data={}]
   * @return {*}  {string}
   * @memberof ResourceScheduleTableController
   */
  getCustomHtml(scriptCode: string, data: any = {}): string {
    return ScriptFactory.execScriptFn(
      {
        data,
        context: this.context,
        params: this.params,
        controller: this,
        ctrl: this,
        view: this.view,
      },
      scriptCode,
      { isAsync: false },
    ) as string;
  }

  /**
   * 保存
   *
   * @param {IData} [config={}]
   * @param {IData[]} [resources=[]]
   * @param {IData[]} [tasks=[]]
   * @return {*}  {boolean}
   * @memberof ResourceScheduleTableController
   */
  async onSave(
    config: IData = {},
    resources: IData[] = [],
    tasks: IData[] = [],
  ): Promise<boolean> {
    await this.handlePresetUILogic('save', {
      tasks,
      config,
      resources,
      data: this.state.data,
    });
    return true;
  }

  /**
   * 另存为
   *
   * @param {IData} [config={}]
   * @param {IData[]} [resources=[]]
   * @param {IData[]} [tasks=[]]
   * @return {*}  {boolean}
   * @memberof ResourceScheduleTableController
   */
  async onSaveAs(
    config: IData = {},
    resources: IData[] = [],
    tasks: IData[] = [],
  ): Promise<boolean> {
    await this.handlePresetUILogic('save_as', {
      tasks,
      config,
      resources,
      data: this.state.data,
    });
    return true;
  }

  /**
   * 资源拖拽前处理，查找自定义部件逻辑标识为reource_create并执行
   *
   * @param {Record<string, any>} dragData
   * @return {*}  {Promise<{ ok: boolean; data: IData }>}
   * @memberof ResourceScheduleTableController
   */
  async beforeResourceDrop(
    dragData: Record<string, any>,
  ): Promise<{ ok: boolean; data: IData }> {
    const result = await this.handlePresetUILogic('resource_create', dragData);
    return result as { ok: boolean; data: IData };
  }

  /**
   * 资源拖拽完成处理，查找自定义部件逻辑标识为resource_completed并执行
   *
   * @param {IScheduleResource} resource
   * @return {*}  {Promise<boolean>}
   * @memberof ResourceScheduleTableController
   */
  async resourceDropCompleted(resource: IScheduleResource): Promise<boolean> {
    const result = await this.handlePresetUILogic(
      'resource_completed',
      resource,
    );
    await this.refresh();
    return result as boolean;
  }

  /**
   * 任务拖拽前处理，查找自定义部件逻辑标识为task_create并执行
   *
   * @param {Record<string, any>} dragData
   * @param {Date} startTime
   * @param {IScheduleResource} resource
   * @return {*}  {Promise<{ ok: boolean; data: IData }>}
   * @memberof ResourceScheduleTableController
   */
  async beforeTaskDrop(
    dragData: Record<string, any>,
    startTime: Date,
    resource: IScheduleResource,
  ): Promise<{ ok: boolean; data: IData }> {
    const result = await this.handlePresetUILogic('task_create', {
      resource,
      data: dragData,
      startTime,
    });
    return result as { ok: boolean; data: IData };
  }

  /**
   * @description 任务更新前处理，查找自定义部件逻辑标识为task_update并执行
   * @param {IScheduleTask} newTask 新任务
   * @param {IScheduleTask} oldTask 旧任务
   * @param {IScheduleResource} newResource 新资源
   * @param {IScheduleResource} oldResource 旧资源
   * @returns {*}  {Promise<{ ok: boolean; data: IData }>}
   * @memberof ResourceScheduleTableController
   */
  async beforeTaskUpdate(
    newTask: IScheduleTask,
    oldTask: IScheduleTask,
    newResource: IScheduleResource,
    oldResource: IScheduleResource,
  ): Promise<{ ok: boolean; data: IData }> {
    const result = await this.handlePresetUILogic('task_update', {
      newTask,
      oldTask,
      newResource,
      oldResource,
    });
    return result as { ok: boolean; data: IData };
  }

  /**
   * 拖拽任务完成处理，查找自定义部件逻辑标识为task_completed并执行
   *
   * @param {IScheduleTask} task
   * @return {*}  {Promise<boolean>}
   * @memberof ResourceScheduleTableController
   */
  async taskDropCompleted(task: IScheduleTask): Promise<boolean> {
    const result = await this.handlePresetUILogic('task_completed', task);
    await this.refresh();
    return result as boolean;
  }

  /**
   * @description 更新任务完成处理，查找自定义部件逻辑标识为task_update_completed并执行
   * @param {IScheduleTask} task
   * @returns {*}  {Promise<boolean>}
   * @memberof ResourceScheduleTableController
   */
  async taskUpdateCompleted(task: IScheduleTask): Promise<boolean> {
    const result = await this.handlePresetUILogic(
      'task_update_completed',
      task,
    );
    await this.refresh();
    return result as boolean;
  }

  /**
   * 处理预置界面逻辑
   *
   * @param {string} tag
   * @param {IData} data
   * @return {*}  {Promise<unknown>}
   * @memberof ResourceScheduleTableController
   */
  async handlePresetUILogic(tag: string, data: IData): Promise<unknown> {
    const logic = this.model.controlLogics?.find(
      item =>
        item.id === tag &&
        item.logicType === 'APPDEUILOGIC' &&
        item.triggerType === 'CUSTOM',
    );
    if (!logic) {
      ibiz.log.warn(`未定义自定义类型部件逻辑[逻辑标识为${tag}]`);
      return { ok: false, data: null };
    }
    const { appDEUILogicId, appDataEntityId } = logic;
    const result = await execUILogic(appDEUILogicId!, appDataEntityId!, {
      context: this.context,
      params: this.params,
      data: [data],
      view: this.view,
      ctrl: this,
    });
    return result;
  }

  /**
   * 执行界面行为
   *
   * @param {string} uiActionId
   * @param {*} item
   * @param {MouseEvent} event
   * @param {string} appId
   * @return {*}  {Promise<void>}
   * @memberof ResourceScheduleTableController
   */
  async doUIAction(
    uiActionId: string,
    item: any,
    event: MouseEvent,
    appId: string,
  ): Promise<void> {
    const eventArgs = this.getEventArgs();
    await UIActionUtil.exec(
      uiActionId!,
      {
        ...eventArgs,
        data: [item],
        context: this.context.clone(),
        params: this.params,
        event,
      },
      appId,
    );
  }

  /**
   * 任务点击
   *
   * @memberof ResourceScheduleTableController
   */
  onTaskClick(data: any): void {
    const navViewMsg = this.getNavViewMsg(data.data, this.context, this.params);
    if (navViewMsg) this._evt.emit('onNavViewChange', { navViewMsg });
  }

  /**
   * 重置导航视图
   *
   * @memberof ResourceScheduleTableController
   */
  onResetNavView(): void {
    const navViewMsg = {
      key: '',
      context: this.context,
      params: this.params,
      viewId: '',
      isCache: false,
    };
    this._evt.emit('onNavViewChange', { navViewMsg });
  }

  /**
   * 获取导航视图信息
   *
   * @author zk
   * @date 2023-06-29 03:06:41
   * @param {IDETabViewPanel} tabViewPanel
   * @return {*}  {Promise<INavViewMsg>}
   * @memberof TabExpPanelController
   */
  public getNavViewMsg(
    data: IData,
    context: IContext,
    params: IParams,
  ): INavViewMsg | undefined {
    const task = this.model.sysCalendarItems?.find(item => {
      return item.id === 'task';
    });
    if (task) {
      const viewModelId = task.navAppViewId;
      const result = this.prepareParams(task!, data, context, params);
      return {
        key: data.srfkey,
        context: result.context,
        params: result.params,
        viewId: viewModelId,
        isCache: false,
      };
    }
  }

  /**
   * 计算导航参数
   *
   * @param {(INavigatable & { appDataEntityId?: string })} XDataModel
   * @param {IData} data
   * @param {IContext} context
   * @param {IParams} params
   * @return {*}  {{ context: IContext; params: IParams }}
   * @memberof ResourceScheduleTableController
   */
  prepareParams(
    XDataModel: INavigatable & { appDataEntityId?: string },
    data: IData,
    context: IContext,
    params: IParams,
  ): { context: IContext; params: IParams } {
    const {
      navDER,
      navFilter,
      navigateContexts,
      navigateParams,
      appDataEntityId,
    } = XDataModel;
    const model = {
      deName: appDataEntityId ? calcDeCodeNameById(appDataEntityId) : undefined,
      navFilter,
      pickupDEFName: (navDER as IDER1N)?.pickupDEFName,
      navContexts: navigateContexts,
      navParams: navigateParams,
    };
    const originParams = {
      context,
      params,
      data,
    };
    const { resultContext, resultParams } = calcNavParams(model, originParams);
    const tempContext = Object.assign(context.clone(), resultContext);
    const tempParams = { ...resultParams };
    return { context: tempContext, params: tempParams };
  }

  /**
   * 设置表格行高
   *
   * @memberof ResourceScheduleTableController
   */
  setTableLineHeight(scale: number): void {
    this._evt.emit('updateTableLineHeight', {
      data: [
        {
          resourceBodyRowHeight:
            (Variables.default.resourceBodyRowHeight / 2) * scale,
        },
      ],
    });
  }

  /**
   * @description 处理配置变更
   * @param {IGlobalConfig} config
   * @memberof ResourceScheduleTableController
   */
  async handleConfigChange(config: IGlobalConfig): Promise<void> {
    // 时间发生变更时刷新
    if (
      config.startTime.getTime() !== this.startTime.getTime() ||
      config.endTime.getTime() !== this.endTime.getTime()
    ) {
      this.startTime = config.startTime;
      this.endTime = config.endTime;
      await this.refresh();
    }
  }

  /**
   * @description 刷新
   * @returns {*}  {Promise<void>}
   * @memberof ResourceScheduleTableController
   */
  async refresh(): Promise<void> {
    await this.loadSchedule(false);
  }
}
